package myjava.overriding;

public class Root2 {

   public static void main(String[] args) {

      A aa = new A();
      B bb = new B();
      A ab = new B();
      
      aa.doIt("");     // ObjectA
      bb.doIt("");     // StringB
      ab.doIt("");     // ObjectA <----

      /*
      L'ULTIMA RIGA CREA PROBLEMI AL PIVELLO

      Ricorda che la jvm va in profondo e esegue sempre la versione overlodata
      Tieni presetne che il processo completo e' in realta' il seguente:

      1 - parti dall'interfaccia che dichiari nel reference type (A in questo caso)
      2 - cerca il metodo che usa una signature coerente con il parametro che passi al metodo
      3 - se lo trovi eseguilo a meno che anche il figlio non abbia un metodo con lo stesso nome - signature
      4 - in tal caso esegui il metodo figlio (overloading method)

      in pratica la questione e' che A.doIt e B.doIt hanno signature diversa
      anche se simile (una e' sottoinsieme dell'altra) e per cui il processo si ferma
      al metodo del padre e stampa Object */

      C cc = new C();
      A ac = new C();

      // qui invece C overraida veramente A.doIt e percio' si ottiene 
      // l'esecuzione del metodo della sottoclasse
      aa.doIt(new Integer(1));   // ObjectA
      cc.doIt(new Integer(1));   // ObjectC
      ac.doIt(new Integer(1));   // ObjectC

      aa.doIt(null);   // ObjectA
      ab.doIt(null);   // ObjectA
      bb.doIt(null);   // StringB
      ac.doIt(null);   // ObjectC
      cc.doIt(null);   // StringC

   }
}

class A {

   void doIt(Object o) {
      System.out.println("ObjectA");
   }
}

class B extends A {
   
   void doIt(String o) {
      System.out.println("StringB");
   }
}

class C extends A {

   @Override
   void doIt(Object o) {
      System.out.println("ObjectC");
   }

   void doIt(String o) {
      System.out.println("StringC");
   }
}